#ifndef __LCD_FSMC_H
#define __LCD_FSMC_H

#include "stm32f4xx.h"
#include "string.h"

// 是否使用DMA
#define USE_FSMC_DMA 1

#if USE_FSMC_DMA
// 使用的DMA流
#define LCD_DMA_Stream		DMA2_Stream6
#define LCD_DMA_Channel		DMA_Channel_0
#define LCD_DMA_IRQn		DMA2_Stream6_IRQn
#define LCD_DMA_IT_TCIFx	DMA_IT_TCIF6
#define LCD_DMA_Handler     DMA2_Stream6_IRQHandler
#endif // USE_FSMC_DMA
//LCD重要参数集
typedef struct  
{
    uint16_t LCD_Width;      //LCD 宽度
    uint16_t LCD_Height;     //LCD 高度
    uint8_t  DIR;        //横屏还是竖屏控制：0，竖屏；1，横屏。
    uint16_t wxram;     // 设置x轴坐标
    uint16_t wyram;     // 设置y轴坐标
    uint16_t setram;    // 写入内存命令
} _lcd_dev;

extern _lcd_dev lcddev;

typedef uint16_t W_Bit;  /* 显示屏宽度位宽 */
typedef uint16_t H_Bit; /* 显示屏高度位宽 */
typedef uint16_t Color_Size; //当前颜色为16位RGB-5-6-5
                       
/* 定义英文字符大小   */
typedef enum{LCD_Char12x24=0,LCD_Char16x32}LCD_CharSize;


/* RGB565 颜色定义 */
#define Block   0x0000      
#define Blue    0x001F
#define Red     0xF800
#define Green   0x07E0
#define Cyan    0x07FF
#define Purple  0xF81F
#define Yellow  0xFFE0
#define White   0xFFFF
#define Gray    0x7BEF
#define Orange  0xFD20
#define Brown   0x8200
#define Pink    0xD2F5

// 设定LCD的地址
volatile typedef struct 
{
    uint16_t LCD_REG;
    uint16_t LCD_DATA;
}LCD_TypeDef;

/* 
LCD的基地址,即RS线为1时为写数据地址，为0时为读数据地址
FSMC使用16位数据线的情况下，HADDR对应到FSMC_Ax的地址需要右移1位
(原本按字节访问,此时相当于地址访问的字节变成了两倍)
这里使用NE1，表示SRAM_BANK1中的区域1
HADDR[27:26] = 11(这里输出11，但是NE是低电平有效，也就是00选择区域1)
参考手册得知Bank1基地址为0x6000 0000 
因为每个Bank大小为0x000 0000 - 0xFFF FFFF,且有四个区域，则每个区域占0x400000
基地址公式: 0x6000 0000+(0x400000 * ((NEx的x) -1)) = 0x6000 0000
FSMC_A16相当于HADDR17，我们操作FSMC时写入的是HADDR的地址
因此实际要访问的地址需要*2,也就是2^16*2 = 0x20000
这个地址就是数据写入的地址(A16 == RS,RS为1写数据)
数据访问地址: 0x6000 0000 + 0x2 0000 = 0x6002 0000
RS为0时就为写命令,故只要次地址小于或不等于0x2 0000就为写命令地址
故我们设置基地址为0x6002 0000 - 2 = 0x6001 FFFE
这样LCD_REG地址为0x6001 FFFE,通过结构体访问DATA时+2字节为0x6002 0000
*/ 
#define LCD   ((LCD_TypeDef *)0x6001FFFE) 


#define LCD_BL_ON   do{ GPIOA->ODR |= (1 << 15); } while(0)
#define LCD_BL_OFF  do{ GPIOA->ODR &= ~(1 << 15); } while(0)


void LCD_Display_on(void);
void LCD_Display_off(void);
void LCD_SetArea(uint16_t LCD_XS,uint16_t LCD_XE,uint16_t LCD_YS,uint16_t LCD_YE);
void LCD_ShowChinese16x16(uint8_t line,uint8_t Column,char *cnstr,uint8_t length,Color_Size Color);
void LCD_ShowChinese32x32(uint8_t line,uint8_t Column,char *cnstr,uint8_t length,Color_Size Color);
void LCD_ShowBinNum(uint8_t line,uint8_t Column,uint16_t BinNum,uint8_t length,Color_Size Color,LCD_CharSize Size);
void LCD_ShowHexNum(uint8_t line, uint8_t column, uint32_t HexNum,uint8_t length, Color_Size Color,LCD_CharSize Size);
void LCD_ShowSignNum(uint8_t line, uint8_t column, int32_t Num,uint8_t length, Color_Size Color,LCD_CharSize Size);
void LCD_ShowNum(uint8_t line, uint8_t column, uint32_t Num,uint8_t length, Color_Size Color,LCD_CharSize Size);
void LCD_ShowChar(uint8_t line,uint8_t column,char Cr,Color_Size Color,LCD_CharSize Size);
void LCD_ShowString(uint8_t line,uint8_t column,char *Str,Color_Size Color,LCD_CharSize Size);

void LCD_Init(void);
void LCD_Display_dir(uint8_t dir);
void LCD_SetBackGround(Color_Size Color);
void LCD_Clear(void);
void LCD_Fill_Color(uint16_t xs,uint16_t ys,uint16_t xe,uint16_t ye,const uint16_t* color);
void LCD_FSMC_Transfer(uint16_t xs,uint16_t ys,uint16_t xe,uint16_t ye,uint16_t *color);

#endif // __LCD_FSMC_H